/** 随机验证码字符串类别枚举
 *
 */
export enum CodeCategory {
  /** 纯数字
   *
   */
  num = 0,

  /** 纯大写字母；
   *
   */
  uppercase,

  /** 纯小写字母；
   *
   */
  lowercase,

  /** 纯字母大小写混合 */
  lettersMix,

  /** 大写字母加数字
   *
   */
  uppercaseAndNum,

  /** 小写字母加数字
   *
   */
  lowercaseAndNum,

  /** 大小写字母加数字
   *
   */
  lettersMixAndNum,
}

/** 字母混合数字枚举
 *
 */
enum LettersCategory {
  /** 大小写混合
   *
   */
  mix = 0,

  /**大写字母
   *
   */
  uppercase,

  /** 小写字母
   *
   */
  Lowercase,
}

/** 选择包含开始和结束的一个随机数
 *
 * @param start 开始
 * @param end 结束
 * @returns 随机数
 */
export const selectRandom = (start: number, end: number): number => {
  const choice = end - start + 1;
  return Math.floor(Math.random() * choice + start);
};

/** 随机选取剩余参数中某个值
 *
 * @param args 多个文本参数
 * @returns {string}
 */
export const selectFromMess = (...args: string[]) => {
  return args[Math.floor(Math.random() * args.length)];
};

/** 验证码类
 *
 */
export class ValidateCode {
  private static readonly BaseCodeByMix: string =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
  private static readonly BaseCodeByMixAndNum: string =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";

  private length: number;
  private codeCategory: CodeCategory;

  /** 验证码类的构造函数
   *
   * @param length  字符串长度
   * @param codeCategory  转换的类别
   */
  constructor(length: number, codeCategory = CodeCategory.lettersMixAndNum) {
    this.length = length;
    this.codeCategory = codeCategory;
  }

  /** 获取验证码 */
  get validateCode() {
    switch (this.codeCategory) {
      case CodeCategory.num:
        return ValidateCode.codeByNum(this.length);
      case CodeCategory.lettersMix:
        return ValidateCode.codeByletters(this.length);
      case CodeCategory.lowercase:
        return ValidateCode.codeByletters(
          this.length,
          LettersCategory.Lowercase
        );
      case CodeCategory.uppercase:
        return ValidateCode.codeByletters(
          this.length,
          LettersCategory.uppercase
        );
      case CodeCategory.lettersMixAndNum:
        return ValidateCode.codeBylettersAndNum(this.length);
      case CodeCategory.lowercaseAndNum:
        return ValidateCode.codeBylettersAndNum(
          this.length,
          LettersCategory.Lowercase
        );
      case CodeCategory.uppercaseAndNum:
        return ValidateCode.codeBylettersAndNum(
          this.length,
          LettersCategory.uppercase
        );
      default:
        const _exhaustiveCheck: never = this.codeCategory;
        return _exhaustiveCheck;
    }
  }

  /** 根据位长产生一个随机数字符串
   *
   * @param length {number} 位长
   * @returns {string} 一个随机数字符串
   */
  static codeByNum(length: number): string {
    let code: string = "";
    for (let i = 0; i < length; i++) {
      code += String(Math.floor(Math.random() * 10)); //产生左闭右开的随机数
    }
    return code;
  }

  /** 纯字母随机数(大小写)
   *
   * @param length 位数
   * @param isaz 是否小写(默认大写)
   */
  static codeByletters(
    length: number,
    lettersCategory: LettersCategory = LettersCategory.mix
  ) {
    let code: string = "";
    for (let i = 0; i < length; i++) {
      // if (!isMix) {
      //   if (isaz) {
      //     code += String.fromCharCode(selectRandom(97, 122));
      //   } else {
      //     code += String.fromCharCode(selectRandom(65, 90));
      //   }
      // } else {
      // }
      let index = Math.floor(Math.random() * this.BaseCodeByMix.length);
      code += this.BaseCodeByMix[index];
    }
    return this.categoryCale(code, lettersCategory);
  }

  /** 字母+数字组成的随机数
   *
   * @param length 字符串长度，位数
   * @param lettersCategory 字母类型(默认大小写混合)
   * @returns
   */
  static codeBylettersAndNum(
    length: number,
    lettersCategory: LettersCategory = LettersCategory.mix
  ) {
    let code: string = "";
    for (let i = 0; i < length; i++) {
      let index: number;
      index = Math.floor(Math.random() * this.BaseCodeByMixAndNum.length);
      code += this.BaseCodeByMixAndNum[index];
    }

    return this.categoryCale(code, lettersCategory);
  }

  /** 根据枚举选择输出文本类型；
   * 私有的静态方法，大写、小写、混合
   * @param code 混合文本
   * @param lettersCategory
   * @returns
   */
  private static categoryCale = (
    code: string,
    lettersCategory: LettersCategory
  ): string => {
    switch (lettersCategory) {
      case LettersCategory.mix:
        return code;
      case LettersCategory.Lowercase:
        return code.toLowerCase();
      case LettersCategory.uppercase:
        return code.toUpperCase();
      default:
        const _exhaustiveCheck: never = lettersCategory;
        return _exhaustiveCheck;
    }
  };
}
